package top.lightHearted.bean;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.kurento.client.Continuation;
import org.kurento.client.MediaPipeline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.PreDestroy;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Room class
 *
 * @author gpf
 * @date 2018/04/16
 */
public class Room implements Closeable {

    private Logger log = LoggerFactory.getLogger(Room.class);

    private MediaPipeline mediaPipeline;

    private String roomName;

    private ConcurrentMap<String, UserSession> participants = new ConcurrentHashMap<>();

    public Room(MediaPipeline mediaPipeline, String roomName) {
        this.mediaPipeline = mediaPipeline;
        this.roomName = roomName;
    }

    public UserSession join(String userName, WebSocketSession session) throws IOException {
        UserSession participant = new UserSession(userName, session, mediaPipeline, roomName);
        joinRoom(participant);
        participants.put(participant.getName(), participant);
        sendParticipantNames(participant);
        return participant;
    }

    public void leave(UserSession user) {
        removeParticipant(user.getName());
        user.close();
    }

    private void removeParticipant(String name) {
        participants.remove(name);

        final List<String> unnotifiedParticipants = new ArrayList<>();
        final JsonObject participantLeftJson = new JsonObject();
        participantLeftJson.addProperty("id", "participantLeft");
        participantLeftJson.addProperty("name", name);
        for (final UserSession participant : participants.values()) {
            try {
                participant.cancelVideoFrom(name);
                participant.sendMessage(participantLeftJson);
            } catch (final IOException e) {
                unnotifiedParticipants.add(participant.getName());
            }
        }

    }


    private void joinRoom(UserSession participant) throws IOException {
        JsonObject newParticipantArrived = new JsonObject();
        newParticipantArrived.addProperty("id", "newParticipantArrived");
        newParticipantArrived.addProperty("name", participant.getName());
        for(UserSession p : participants.values()){
            participant.sendMessage(newParticipantArrived);
        }
    }



    private void sendParticipantNames(UserSession user) throws IOException {
        final JsonArray participantsArray = new JsonArray();
        for (final UserSession participant : participants.values()) {
            if (!participant.equals(user)) {
                final JsonElement participantName = new JsonPrimitive(participant.getName());
                participantsArray.add(participantName);
            }
        }

        final JsonObject existingParticipantsMsg = new JsonObject();
        existingParticipantsMsg.addProperty("id", "existingParticipants");
        existingParticipantsMsg.add("data", participantsArray);
        user.sendMessage(existingParticipantsMsg);
    }

    @PreDestroy
    private void shutdown() {

    }


    public MediaPipeline getMediaPipeline() {
        return mediaPipeline;
    }

    public void setMediaPipeline(MediaPipeline mediaPipeline) {
        this.mediaPipeline = mediaPipeline;
    }

    public String getRoomName() {
        return roomName;
    }

    public void setRoomName(String roomName) {
        this.roomName = roomName;
    }

    public ConcurrentMap<String, UserSession> getParticipants() {
        return participants;
    }

    public void setParticipants(ConcurrentMap<String, UserSession> participants) {
        this.participants = participants;
    }

    @Override
    public void close() throws IOException {
        for(UserSession participant: participants.values()){
            participant.close();
        }
        participants.clear();
        mediaPipeline.release(new Continuation<Void>() {
            @Override
            public void onSuccess(Void aVoid) throws Exception {

            }

            @Override
            public void onError(Throwable throwable) throws Exception {

            }
        });
    }
}



